package com.devil.assistant.advisor;

import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.ai.chat.client.advisor.api.AdvisedRequest;
import org.springframework.ai.chat.client.advisor.api.AdvisedResponse;
import org.springframework.ai.chat.client.advisor.api.StreamAroundAdvisor;
import org.springframework.ai.chat.client.advisor.api.StreamAroundAdvisorChain;
import reactor.core.publisher.Flux;

/**
 * 流式处理日志增强切面顾问
 *
 * <p>实现流式处理全生命周期的日志跟踪能力，作为Spring Cloud Stream的增强组件，
 * 在消息流的处理链中注入日志切面，提供可观测性支持。</p>
 *
 * <h3>核心职责：</h3>
 * <ul>
 *   <li>记录流式请求的元数据（入参、上下文等）</li>
 *   <li>透传处理链保证消息流连续性</li>
 *   <li>支持多切面执行顺序控制（通过getOrder()调节优先级）</li>
 * </ul>
 *
 * @see StreamAroundAdvisor 流式切面顾问标准接口
 * @see AdvisedRequest 增强请求包装对象（包含消息头/体）
 * @see StreamAroundAdvisorChain 处理链上下文（责任链模式实现）
 * @author Devil
 * @version 1.0
 * @date 2025/4/11 21:48
 */
@Slf4j
public class LoggingAdvisor implements StreamAroundAdvisor {

    /**
     * 环绕式流处理增强（DEBUG级别日志记录）
     *
     * <p>在流处理链执行前后添加日志跟踪点，注意：</p>
     * <ul>
     *   <li>采用Reactive模式，需确保日志记录操作符的正确位置</li>
     *   <li>通过chain.nextAroundStream()保持流处理连续性</li>
     *   <li>DEBUG级别日志避免记录敏感数据或过大消息体</li>
     * </ul>
     *
     * @param advisedRequest 增强请求对象（包含消息上下文）
     * @param chain 处理链执行器（触发下一个切面/最终处理器）
     * @return 响应流（保持背压传递特性）
     */
    @NotNull
    @Override
    public Flux<AdvisedResponse> aroundStream(@NotNull AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
        log.debug("request: {}", advisedRequest); // 记录请求快照
        return chain.nextAroundStream(advisedRequest); // 透传处理链
    }

    /**
     * 切面执行顺序（默认最高优先级）
     *
     * <p>数值越小优先级越高，建议：</p>
     * <ul>
     *   <li>日志切面通常设置为最早执行（最小数值）</li>
     *   <li>安全校验类切面可设置为更高优先级（更小数值）</li>
     * </ul>
     *
     * @return 执行顺序标识（Spring OrderUtils优先级规范）
     */
    @Override
    public int getOrder() {
        return 0; // 最高优先级执行
    }

    /**
     * 获取切面标识（默认使用类全限定名）
     *
     * <p>用于：</p>
     * <ul>
     *   <li>监控系统显示切面名称</li>
     *   <li>动态配置排除特定切面</li>
     *   <li>异常堆栈定位问题切面</li>
     * </ul>
     *
     * @return 切面唯一标识符
     */
    @NotNull
    @Override
    public String getName() {
        return this.getClass().getName(); // 使用类名保证唯一性
    }
}
